/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:itsm-gateway
 * Create Time: 2016年3月18日 下午5:42:32
 */
package com.lenovo.lmrp.server.itsmgateway.adapter.ms;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lenovo.lmrp.api.model.entity.AttachmentPO;
import com.lenovo.lmrp.api.model.entity.AttachmentPO.AttachmentStatus;
import com.lenovo.lmrp.server.itsmgateway.adapter.AItsmAdapter;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.ICommonDAO;
import com.lenovo.sdc.framework.dao.RecordFilter;
import com.lenovo.sdc.framework.scheduler.ACommonTask;
import com.lenovo.sdc.framework.scheduler.Schedule;
import com.lenovo.sdc.framework.util.Condition;
import com.lenovo.sdc.framework.util.Condition.OperatorEnum;
import com.lenovo.sdc.framework.util.Tuple;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * Schedule task to upload un-synced file to ITSM system.
 * 
 * Load ticket attachment from db that status is AttachmentStatus.UPLOADED
 * then invoke adapter interface to upload file
 * 
 * @author wujin
 * @version v1.0
 */
public class SyncAttachmentTask extends ACommonTask {
    private static final Logger logger = LoggerFactory.getLogger(SyncAttachmentTask.class);
    private static final int ONE_MINUTE = 60;
    
    private String taskID;
    private String itsmCode;
    private AItsmAdapter adapter;
    private ADaoFactory daoFactory;
    
    private int currentSchedule;
    private List<Schedule> scheduleCandidate;
    
    public SyncAttachmentTask(String itsmCode, ADaoFactory daoFactory, AItsmAdapter adapter) {
        super();
        this.itsmCode = itsmCode;
        this.daoFactory = daoFactory;
        this.adapter = adapter;
        
        scheduleCandidate = new ArrayList<>(5);
        scheduleCandidate.add(new Schedule(ONE_MINUTE));
/*        for (int i = ONE_MINUTE; i <= 960; i *= 2)
            scheduleCandidate.add(new Schedule(i));*/
        
        this.currentSchedule = 0;
        this.taskID = itsmCode + ":syncattachmemt:" + System.currentTimeMillis();
    }

    @Override
    public String getID() {
        return taskID;
    }

    @Override
    public Schedule getSchedule() {
        return scheduleCandidate.get(currentSchedule);
    }
    
    @Override
    public void execute() throws Exception {
        try (ICommonDAO dao = daoFactory.createDAO(itsmCode)) {
            RecordFilter filter = new RecordFilter();
            filter.addCondition(new Condition<String, Object>("status", AttachmentStatus.UPLOADED));
            filter.addCondition(new Condition<String, Object>("updatetime", new Date(System.currentTimeMillis() - 7200000),OperatorEnum.GT));
            List<AttachmentPO> attachs = dao.filteByCondition(AttachmentPO.class, filter);
            
            // when not attachment to upload, extend waiting time until the max schedule interval
            if (attachs.size() == 0) {
                if (currentSchedule >= scheduleCandidate.size() - 1)
                    currentSchedule = scheduleCandidate.size() - 1;
                else
                    currentSchedule ++;
                
                return;
            }

            logger.info("find {} attachments need to sync", attachs.size());
            int counter = 0;
            for (AttachmentPO po : attachs) {
                try {
                    Tuple.Pair<Boolean, String> result = adapter.uploadTicketAttachment(po);
                    if (result.getOne() == false) {
                        logger.warn("upload attachment {} to {} meet error {}", po.getFileName(), itsmCode, result.getSecond());
                        continue;
                    }
                    else {
                        po.setStatus(AttachmentStatus.SYNCED);
                        po.setUpdateTime(new Date());
                        
                        dao.beginTrans();
                        dao.update(po);
                        dao.endTrans();
                        counter ++;
                    }
                }
                catch (Exception exp) {
                    logger.warn("upload attachment {} to {} meet error {}", po.getFileName(), itsmCode, exp.getMessage());
                    continue;
                }
            }
            logger.info("complete sync {} attachments to {}", counter, itsmCode);
            
            attachs.clear();
            
            // after upload attachment should short waiting time until the min schedule interval
            currentSchedule --;
            if (currentSchedule < 0)
                currentSchedule = 0;
        }
        catch (Exception exp) {
            TraceableException.writeLog(ErrorCode.NET_WRITE_ERROR, "failed upload attachment to " + itsmCode, exp);
        }
    }
}
